from abc import ABCMeta, abstractmethod
import logging
import time


"""设计要点：两个核心对象（进行池化的对象、对象池）、三个关键动作对象（借用对象、使用对象、归还对象）
   使用注意事项：对已归还的对象的引用，不能在进行任何其他操作，否则将产生不可预料的结果（使用引用计数技术sys.getrefcount())
   应用场景：适用于那些初始化和销毁的代价高且需要经常被实例化的对象，如大对象、需占用I/O的对象
   实际应用：线程池、连接池等
"""


# 打印INFO以上的信息
logging.basicConfig(level=logging.INFO)


class PooledObject:
    """池对象，池化对象"""
    def __init__(self, obj):
        self.__obj = obj
        self.__busy = obj

    def getObject(self):
        return self.__obj

    def setObject(self, obj):
        self.__obj = obj

    def isBusy(self):
        return self.__busy

    def setBusy(self, busy):
        return self.__busy = busy


class ObjectPool(metaclass=ABCMeta):
    """对象池"""
    """对象池初始化大小"""
    InitialNumOfObjects = 10
    """对象池的大小"""
    MaxNumOfObjects = 50

    def __init__(self):
        self.__pools = []
        for i in range(ObjectPool.InitialNumOfObjects):
            obj = createPoolObject()
            self.__pools.append(obj)

    @abstractmethod
    def createPoolObject(self):
        pass

    def borrowObject(self):
        """借用独享"""
        # 如果找到空闲对象，直接返回
        obj = self.__findFreeObject()
        if obj is not None:
            logging.info("%x对象已被借用，time:%s", id(obj), time.strftime(r"%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
            return obj
        # 如果对象池还未满，则添加新的对象
        if(len(self.__pools) < ObjectPool.MaxNumOfObjects):
            pooledObj = self.addObject()
            if pooledObj is not None:
                pooledObj.setBusy(True)
                logging.info("%x对象已被借用，time:%s", id(obj), time.strftime(r"%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
                return pooledObj.getObject()
        return None

    def returnObject(self, obj):
        """归还对象"""
        for pooledObj in self.__pools:
            if(pooledObj.getObject() == obj):
                pooledObj.setBusy(False)
                logging.info("%x对象已被归还，time:%s", id(obj), time.strftime(r"%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
                break

    def addObj(self):
        """添加新对象"""
        obj = None
        if(len(self.__pools)<ObjectPool.MaxNumOfObjects):
            obj = self.createPoolObject()
            self.__pools.append(obj)
            logging.info("添加新对象%x，time:%s", id(obj), time.strftime(r"%Y-%m-%d %H:%M:%S", time.localtime(time.time())))
            return obj

    def clear(self):
        """清空对象池"""
        self.__pools.clear()

    def __findFreeObject(self):
        """查找闲置对象"""
        obj = None
        for pooledObj in self.__pools:
            if not pooledObj.isBusy():
                obj = pooledObj.getObject()
                pooledObj.setBusy(True)
                break
        return obj

